import {
    init
} from 'snabbdom/build/package/init'
import {
    h
} from 'snabbdom/build/package/h'
import {
    classModule
} from 'snabbdom/build/package/modules/class'
import {
    eventListenersModule
} from 'snabbdom/build/package/modules/eventlisteners'
import {
    styleModule
} from 'snabbdom/build/package/modules/style'

import originData from './data.json'
import './style.css'

const patch = init([classModule, styleModule, eventListenersModule])
let oldVnode = document.querySelector('#app')
let data = originData

let vnode

// 列表每项的margin值
var margin = 8
let newKey = 11
let orderBy = 'rank'

function movieList() {

    return data.map(movie => {
        return h('li.row', {
            key: movie.rank,
            style: {
                opacity: '0',
                transform: 'translate(-200px,0)',
                // 下一帧
                delayed: {
                    transform: `translate(0,${movie.offset||0}px)`,
                    opacity: '1'
                },
                remove: {
                    transform: `translate(200px,0)`,
                    opacity: '0'
                }

            },
            hook: {
                // 当元素已经插入到DOM上  修改movie.eleHeight
                insert(vnode) {
                    movie.elmHeight = vnode.elm.offsetHeight
                }
            }

        }, [
            h('div.rank', movie.rank),
            h('div.title', movie.title),
            h('div.desc', movie.desc),
            h('div.delete', {
                on: {
                    // snabbdom2.x 版本 移除了 {click:[handler,arg1,..]}的写法  https://github.com/snabbdom/snabbdom/blob/master/CHANGELOG.md#200-2020-09-10   
                    // https://github.com/snabbdom/snabbdom/issues/802
                    // 需要传递参数 可以写成 {click:handler.bind(ctx,arg1,arg2...)} 或  { click: () => { handler(id) }
                    click: () => delMovie(movie)
                }
            }, 'X')
        ])
    })
}

function render() {
    // 计算每个元素的位置
    // 第一个元素offset是0 
    // 之后是上一个元素的offset+margin
    data = data.reduce((acc, movie) => {
        const last = acc[acc.length - 1] //上一个元素
        movie.offset = last ? last.offset + last.elmHeight + margin : 0
        return acc.concat(movie)
    }, [])
    vnode = newVnode()
    oldVnode = patch(oldVnode, vnode)
}

function newVnode() {
    return h('div#app.container', [
        h('h1', `Top ${data.length} movies`),
        h('div', [
            h('span', 'Sort by: '),
            h('span.btn', {
                class:{
                    active:orderBy === 'rank'
                },
                on: {
                    click: () => changeSort('rank')
                }
            }, 'Rank'),
            h('span.btn', {
                class:{
                    active:orderBy === 'title'
                },
                on: {
                    click: () => changeSort('title')
                }
            }, 'Title'),
            h('span.btn', {
                class:{
                    active:orderBy === 'desc'
                },
                on: {
                    click: () => changeSort('desc')
                }
            }, 'Description'),
            h('span.btn.add', {
                on: {
                    click: addMovie
                }
            }, 'Add'),
        ]),
        h('ul', movieList())
    ])
}

// 添加
function addMovie() {
    let index = Math.floor(10 * Math.random(0, 1))
    let m = originData[index]
    let movie = {
        rank: newKey++,
        title: m.title,
        desc: m.desc,
        elmHeight: m.elmHeight || 0
    }
    data.unshift(movie)
    // movie有值 说明之前渲染过，直接拿到高度渲染
    // 如果movie的没有值，需要渲染两次 第一次拿到elmHeight值，第二次将所有的movie渲染到正确的位置
    if(!movie.elmHeight){
        render()
    }
    render()
}
// 删除
function delMovie(movie) {
    data = data.filter(m => {
        return movie !== m
    })
    render()
}

// 排序
function changeSort(key) {
    orderBy = key
    data.sort((a, b) => {
        if (a[key] < b[key]) return -1
        else if (a[key] > b[key]) return 1
        return 0
    })
    render()
}


// 第一次渲染  ，拿到每个 movie.elmHeight  所有movie的offset值是0 
vnode = newVnode()
oldVnode = patch(oldVnode, vnode)
// 根据movie.elmHeight 重新将movie渲染到正确的位置
render()